#include "app_pool.h"
#include "log/log.h"
#include <pthread.h>
#include <stdlib.h>
#include <mqueue.h>

static pthread_t * thread_pool;  //线程池容器（数组）
static int thread_num = 0;  //线程池线程数
static char * mq_name = "/gateway_mq";  //消息队列名称 /是/dev/mqueue/目录
static mqd_t mq_fd;  //消息队列描述符

//线程池中的线程函数，不断从消息队列中取任务执行(接收到消息就执行)
void *thread_func(void *arg){
    //一个线程一个函数一个任务
    Task task;
    //这个while就不会结束，取到了仍然会继续取
    while(1){
        //从消息队列中取任务，参数要求转为char*
        ssize_t len= mq_receive(mq_fd, (char *)&task, sizeof(Task), NULL);
        //取到任务才执行（-1失败）
        if(len ==sizeof(Task)){
            //执行任务（两个结构体成员互相套）
            task.task_func(task.arg);
        }
    }
}


//初始化：创建线程池、消息队列、监听消息队列有任务则接收
int app_pool_init(int num){
    //创建线程池
    thread_num = num;
    //分配n个线程空间给线程数组
    thread_pool = malloc(sizeof(pthread_t) * num);
    //把数组线程元素创建出来
    for(int i = 0; i < num; i++){
        //创建线程
        pthread_create(&thread_pool[i], NULL, thread_func, NULL);
    }

    //队列属性
    struct mq_attr attr;    
    attr.mq_maxmsg= 10;  //最大消息数
    attr.mq_msgsize=sizeof(Task);  //消息大小是结构体大小

    //创建消息队列（读写+创建文件，全部人都读写权限）
    mq_fd = mq_open(mq_name, O_RDWR|O_CREAT, 0666, &attr);

    if(mq_fd == -1){
        log_error("消息队列创建失败！\n");
        return -1;
    }
    return 0;
}

//关闭：销毁线程池、消息队列
void app_pool_close(void){
    //销毁线程池
    for(int i = 0; i < thread_num; i++){
        pthread_cancel(thread_pool[i]);
        //防止主线程打断销毁分线程
        pthread_join(thread_pool[i], NULL);
    }
    free(thread_pool);
    //销毁消息队列
    mq_close(mq_fd);
    mq_unlink(mq_name);
}

//注册回调：将任务函数结构体注册/发送到消息队列中、等待某监听线程执行任务
//没直接用Task * task是因为Task * task线程池释放会没
int app_pool_registerTask(int (*tast_func)(void *arg), void *arg){
    //创建任务
    Task task;
    task.task_func = tast_func;
    task.arg = arg;
    //发送消息到消息队列(发送任务结构体，优先级随便，参数要求转为char*)
    mq_send(mq_fd, (char *)&task, sizeof(Task), 1);
}

